
#ifndef BSHEDULER_H_
#define BSHEDULER_H_

#include "BSysDefs.h"

using namespace blueberry::utl;

typedef std::set<UInt> ONR2S_CLIENTS;
typedef std::set<UInt> DELETED_TIMERS;
typedef std::set<UInt> DELETED_CLIENTS;
typedef std::set<UInt> DELETED_SERVERS;
typedef std::set<UInt> WRITE_DESCON_CLIENTS;
typedef std::stack<UInt> FREE_TIMER_IDS;
typedef std::set<UInt> ACTIVE_CLIENTS;
#ifndef _ALL_HB_CLIENTS_
#define _ALL_HB_CLIENTS_
typedef std::set<UInt> ALL_HB_CLIENTS;
#endif

namespace blueberry
{
		class BScheduler;
		class BClient;
		class BServer;
		class BTimer;
		class BMCPktCache;

		typedef struct _st_TimerBox
		{
			UInt ui_TimerID;
			BTimer * p_Timer;

			_st_TimerBox(UInt _uiID, BTimer * _pTimer)
			{
				ui_TimerID = _uiID;
				p_Timer = _pTimer;
			}
		} st_TimerBox;
		typedef std::list<st_TimerBox *> TIMER_LIST;
		typedef std::list<BClient*> T_LST_CLIENTS;
		typedef enum BErrTag
		{
			EVTERR_NONE = 1, // No errors
			EVTERR_CANT_INIT_SOCKETS,
			EVTERR_SOCKET, // Error report by sockets
			EVTERR_TIMEOUT, // Connection timeout
			EVTERR_CLOSED, // connection closed
			EVTERR_BUFFERED,
			EVTERR_HB_MISSED,
			EVTERR_HB_EXPIRED,
			EVTERR_INVALID_PARAMETERS,
			EVTERR_CANNOT_INIT_HB_TIEVTERR,
			EVTERR_LOOP_EXIT,
			EVTERR_DATA_NOT_SENT,
			EVTERR_CANT_INIT_LZO

		} BErr;

		class BTimerCallback
		{
		public:
			BTimerCallback(){};
			virtual ~BTimerCallback();
			virtual void OnTimer(BTimer * _pTimer) = 0;
		};

		class BServerCallback
		{
		public:
			BServerCallback()	{}	;
			virtual ~BServerCallback(){};
			virtual void OnData(BServer * _pServer, BClient * _pClient, char * _zData, int _iLen) = 0;
			virtual void OnConnect(BServer * _pServer, BClient * _pClient) = 0;
			virtual void OnDisconnect(BServer * _pServer, BClient * _pClient, BErr _Err) = 0;
			virtual void OnReadyToSend(BServer * _pServer, BClient * _pClient) = 0;
		};

		class BClientCallback
		{
		public:
			BClientCallback(){};
			virtual ~BClientCallback(){};
			virtual void OnData(BServer * _pServer,BClient * _pClient,char * _zData, int _iLen);
			virtual void OnData(BClient * _pClient,char * _zData, int _iLen);
			virtual void OnDisconnect(BServer * _pServer,BClient * _pClient ,BErr _Err);
			virtual void OnDisconnect(BClient * _pClient,BErr _Err);
			virtual void OnReadyToSend(BClient * _pClient);
		};


		class BTimer:public BItem
		{
		public:
			BTimer(UInt _uiInterval,BTimerCallback * _pTCB,bool _bIsRepeated,UInt _uiTimerID,BScheduler * _pEventMan, int _iTimerType = -1);
			virtual ~BTimer();
			inline UInt GetInterval(){return ui_Interval;};
			inline UInt GetNextFire(){return ui_NextFire;};
			inline UInt GetTimerID(){return ui_TimerID;};

			inline void SetNextFire(UInt _uiFireTime){ui_NextFire = _uiFireTime; };
			inline BTimerCallback * GetTimerCB(){return p_TimerCB;};

			inline void ResetTimerId(){ui_TimerID = 0;};
			inline bool IsRepeated(){return b_IsRepeated ;};
			inline void SetIsRemovedTimer(bool _State){b_IsRemovedTimer = _State ;};
			void * p_Data;
			int i_TimerType;
		private:
			bool b_IsRepeated;
			bool b_IsRemovedTimer;
			UInt ui_Interval;
			BTimerCallback * p_TimerCB;
			BScheduler * p_EventMan;
			UInt ui_NextFire;
			UInt ui_TimerID;

		};

		class BClient:public BItem
		{
		public:
			BClient(const char * _zIP,UInt _uiPort,UInt _uiClientID ,bool _bHB,BClientCallback * _pCCB,BScheduler * _pEventMan,BServer * _pServer);
			virtual ~BClient();

			bool Send(const char * _zData, int _iLen);
			void SendBufferedData();
			void Detach();

			inline UInt GetClientID(){return ui_ClientID;}
			inline BClientCallback * GetClientCB(){return p_ClientCB ;}
			inline BServer * GetServer(){return p_Server; }
			inline void SetServer(BServer * _pServer) { p_Server = _pServer; }
			inline void SetEventSheduler(BScheduler * _pEvtShed) { p_Scheduler = _pEvtShed; }
			inline const char * GetClientAddress() const { return z_ServerIP; }
			inline UInt GetClientPort()const {return ui_ServerPort;}
			inline void SetCCB(BClientCallback * _pCCB) {p_ClientCB =_pCCB; }
			inline bool IsHBEnable(){ return b_HB; }
			inline bool IsBuffered(){return b_IsBuffered ;}
			inline void SetBufferStatus(bool _bStatus){ b_IsBuffered = _bStatus ;}

			void SetSocketSendBufferSize(UInt _uiSize);
			void SetSocketRecvBufferSize(UInt _uiSize);

			BNormBuffer m_SendBuffer;
			BNormBuffer m_RcvBuffer;
			void * p_Data;

		protected:

			UInt ui_ClientID; //socket descriptor
			bool b_HB;
			bool b_IsBuffered;
			UInt ui_ServerPort;
			char z_ServerIP[MAX_IP_ADDRESS_LEN];
			BClientCallback * p_ClientCB;
			BScheduler * p_Scheduler;
			BServer * p_Server;

		};

		class BServer:public BItem
		{
		public:
			BServer(UInt _uiPort,bool _bHB, UInt _uiServerID, BServerCallback * _pSCB, BScheduler * _pEventMan);
			virtual ~BServer();
			inline UInt GetServerID(){return ui_ServerID;};
			inline UInt GetServerPort(){return ui_ServerPort;};
			inline BServerCallback * GetServerCB(){return p_ServerCB;};
			void AddToClientSet(UInt _uiClientID){set_ActiveClients.insert(_uiClientID);};
			void RemoveFromClientSet(UInt _uiClientID){set_ActiveClients.erase(_uiClientID);};
			void CloseServerSocket();
			inline bool IsHBEnable(){ return b_HB;};
			void AddtoConnectedClientsList(BClient* _pClient);
			void RemoveFromConnectedClientsList(BClient* _pClient);
			void SendToAllClients(const char * _zBuf, UInt _uiLen);

			void * p_Data;

		private:
			bool b_HB;
			UInt ui_ServerPort;
			UInt ui_ServerID; //socket descriptor
			BServerCallback * p_ServerCB;
			BScheduler * p_EventMan;
			ACTIVE_CLIENTS set_ActiveClients;
			T_LST_CLIENTS lst_ConnectedClients;//Set by application layer
		};

		class BMulticastSender: public BServerCallback
			{
			public:
				BMulticastSender(const char* _zMulticastGroupIP, int _iMulticastPort, UInt _uiCacheSize);
				~BMulticastSender();
				inline int GetIntendedPort()const{ return i_IntendedPort; };
				inline const char * GetMulticastPort()const { return z_MulticastGroupIP;}
				void CheckAndSetMulticastInfo(UInt _uiMCGroupIP, UShort _usMCPort);
				void MulticastPacket(const char * _zData, int _iDataLen);
				void MulticastRawData( const char * _zData, int _iDataLen);//For sending raw data
				int i_IntendedPort;
				int i_MCasterSocFD;
				char z_MulticastGroupIP[ MAX_IP_ADDRESS_LEN ];
			private:

				UInt ui_MulticastGroupIP;
				struct sockaddr_in m_StSocAddr;
				UInt ui_SecNumber;
				char z_SendBuf[B_PKT_SEND_SIZE_MAX];
				BMCPktCache * p_PktCache;
				typedef void (BMulticastSender::*fpT_RequestProcessors)(char *, UInt,BClient*);
				void OnData(BServer * _pServer, BClient * _pClient, char * _zData, int _iLen);
				void OnConnect(BServer * _pServer, BClient * _pClient);
				void OnDisconnect(BServer * _pServer, BClient * _pClient, BErr _Err);
				void OnReadyToSend(BServer * _pServer, BClient * _pClient);
				void RetransPulseProcessor(char * _zBuffer, UInt _uiLen,BClient* _pClient);
				void RetransEmptyProcessor(char * _zBuffer, UInt _uiLen,BClient* _pClient);
				void RetransGapReqProcessor(char * _zBuffer, UInt _uiLen,BClient* _pClient);

			};


		class BScheduler: public BTimerCallback
		{
		public:
			BScheduler();
			virtual ~BScheduler();
			void Run();
			BTimer * CreateTimer(double _dIntaval, bool _bIsRepeated, BTimerCallback * _pTCB, int _iTimerType = -1);
			BServer * CreateServer(UInt _uiPort, BServerCallback * _pSCB, bool _bHB = false);
			BClient * CreateClient(const char * _zServerIP, UInt _uiServerPort, BClientCallback * _pCCB, bool _bHB);

			BMulticastSender * CreateMCastSender(const char * _zMCastGroupIP, int _iMCastPort, UInt _uiCacheSize, int _iRetransPort);
			void CreateLog(const char * _zLogFileName);
			void AddToDeletedTimerSet(UInt _uiTimerID);
			void AddToDeletedClientSet(UInt _uiClientID);
			void AddToDeletedServerSet(UInt _uiServerID);
			int SendToClient(UInt _uiClid);

			void Detach(BClient * _pClient);
			void AttachClient(BClient * _pClient,BClientCallback * _pCCB);

			inline void SetReadTurns(int _iRdTurns){i_ReadTurns = _iRdTurns ;};

			void SetLogDumpStatus(bool _bStatus){ b_ISSocketLogDump = _bStatus ;};
			void SetLogON();
			void SetLogOff();

			static int SetLimits(unsigned int _uiSoftLimit, unsigned int _uiHardLimit);

		private:
			//void OnTimer(BTimer * _pTimer);
			void AddToTimerList(BTimer * _pTimer);
			void AddToCorrectSlot(st_TimerBox * _pstTimeBox);

			void SetSocketOptions(int _iSockID);
			void SetNonBlocking(int _iSockID);
			void WriteSockLog(bool _bIn, int _iCliId, const char* _zBuff, int _iBufLen);

			UInt ReadSockets(UInt _uiInterval);
			int GetTimerIDFromStack();

			bool IsTimerLive(UInt _uiTimerID);
			UInt FireAll();

			UInt ui_CurrentPos;
			UInt ui_LastTime;
			UInt ui_CurrTime;

			UInt ui_TotalDeviation;
			UInt ui_MicroSec;
			int i_TotMicroSec;
			int i_ReadTurns;

			struct timeval tvnow;
			int i_MaxTimers;
			BTimer ** ap_Timers;
			FREE_TIMER_IDS stack_FreeTimerIDs;
			TIMER_LIST ast_Timers[MAX_ARRAY_SIZE];
			TIMER_LIST lst_FireAll;
			BTimer * p_HBTimer;

			int i_EpollFd;
			int i_CliAddrSize;
			struct sockaddr_in stCliAddr;

			struct epoll_event * pstEpollRetEvents;
			BItem ** ap_EItems;
			char z_ReadBuff[CLI_READ_SIZE];
			WRITE_DESCON_CLIENTS set_DiconClients;
			ONR2S_CLIENTS set_OnReadyToSendClients;

			char z_HeartBeat[32];
			//int i_HBLen;
			ALL_HB_CLIENTS set_HBClients;
			bool b_ISSocketLogON;
			bool b_ISSocketLogDump;

			int i_SockLogFd;
			char z_SockLogPath[1024];
			int i_LocalSeconds;
			char z_LocalTimeStamp[25];
			char z_SockLogBuff[40];
		};

		class BMCPktCache
			{
			public:
				BMCPktCache(UInt _uiCacheSize);
				void InsertItem(const char * _zBuffer, int _iBufLen, UInt _uiSeqNo);
				BFixedBuffer * GetItem(UInt _uiSeqNo);
				typedef void (BMCPktCache::*pfT_BufferProcessor)(const char * ,int ,UInt );
				pfT_BufferProcessor pf_CurrentBufferProcessor;
				void PrintValue();//Just a utility method
			private:
				void InsertInitialItem(const char * _zBuffer, int _iBufLen, UInt _uiSeqNo);
				void InsertItemAtHalfFilled(const char * _zBuffer, int _iBufLen, UInt _uiSeqNo);
				void InsertItemAtFullFilled(const char * _zBuffer, int _iBufLen, UInt _uiSeqNo);
				BFixedBuffer ** ap_CachedPackets;
				UInt ui_MinAvailSeqNo, ui_MaxAvailSeqNo;
				UInt ui_CacheSize;

			};

}  // namespace blueberry

#endif /* EVTSHEDULER_H_ */
